#include "VDecode.h"
#include "verilated.h"
#include "svdpi.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>
#include "VDecode___024root.h"

#define BITMASK(bits) ((1ull << (bits)) - 1)
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
#define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })

#define immI()                       \
  do                                 \
  {                                  \
    imm = SEXT(BITS(i, 31, 20), 12); \
  } while (0)
#define immU()                             \
  do                                       \
  {                                        \
    imm = SEXT(BITS(i, 31, 12), 20) << 12; \
  } while (0)
#define immS()                                              \
  do                                                        \
  {                                                         \
    imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); \
  } while (0)
#define immJ()                                                                                                              \
  do                                                                                                                        \
  {                                                                                                                         \
    imm = SEXT(((BITS(i, 31, 31) << 20) | (BITS(i, 30, 21) << 1) | (BITS(i, 20, 20) << 11) | (BITS(i, 19, 12) << 12)), 21); \
  } while (0)
#define immB()                                                                                                          \
  do                                                                                                                    \
  {                                                                                                                     \
    imm = SEXT(((BITS(i, 31, 31) << 12) | (BITS(i, 30, 25) << 5) | (BITS(i, 11, 8) << 1) | (BITS(i, 7, 7) << 11)), 13); \
  } while (0)

extern "C"
{
  typedef union
  {
    uint32_t inst;
    struct
    {
      uint32_t op_code : 7;
      uint32_t rd : 5;
      uint32_t funct3 : 3;
      uint32_t rs1 : 5;
      uint32_t rs2 : 5;
      uint32_t funct7 : 7;
    } inst_R;
    struct
    {
      uint32_t op_code : 7;
      uint32_t rd : 5;
      uint32_t funct3 : 3;
      uint32_t rs1 : 5;
      uint32_t imm_11_0 : 12;
    } inst_I;
    struct
    {
      uint32_t op_code : 7;
      uint32_t imm_4_0 : 5;
      uint32_t funct3 : 3;
      uint32_t rs1 : 5;
      uint32_t rs2 : 5;
      uint32_t imm_11_5 : 7;
    } inst_S;
    struct
    {
      uint32_t op_code : 7;
      uint32_t imm_11 : 1;
      uint32_t imm_4_1 : 4;
      uint32_t funct3 : 3;
      uint32_t rs1 : 5;
      uint32_t rs2 : 5;
      uint32_t imm_10_5 : 6;
      uint32_t imm_12 : 1;
    } inst_B;
    struct
    {
      uint32_t op_code : 7;
      uint32_t rd : 5;
      uint32_t imm_31_12 : 20;
    } inst_U;
    struct
    {
      uint32_t op_code : 7;
      uint32_t rd : 5;
      uint32_t imm_19_12 : 8;
      uint32_t imm_11 : 1;
      uint32_t imm_10_1 : 10;
      uint32_t imm_20 : 1;
    } inst_J;
  } Instruction;

  int64_t get_imm_I(Instruction inst)
  {
    uint32_t i = inst.inst;
    int64_t imm;
    immI();
    return imm;
  }
  int64_t get_imm_U(Instruction inst)
  {
    uint32_t i = inst.inst;
    int64_t imm;
    immU();
    return imm;
  }
  int64_t get_imm_S(Instruction inst)
  {
    uint32_t i = inst.inst;
    int64_t imm;
    immS();
    return imm;
  }
  int64_t get_imm_J(Instruction inst)
  {
    uint32_t i = inst.inst;
    int64_t imm;
    immJ();
    return imm;
  }
  int64_t get_imm_B(Instruction inst)
  {
    uint32_t i = inst.inst;
    int64_t imm;
    immB();
    return imm;
  }
}
struct
{
  uint32_t inst;
  char name[16];
  char type[16];
} insts[] = {
    {0b00000000000000000000000000010111, "auipc", "U"},
    {0b00000000000000000000000000110111, "lui", "U"},
    {0b00000000000000000000000000011011, "addiw", "I"},
    {0b00000000000000000000000000111011, "addw", "R"},
    {0b00000000000000000011000000000011, "ld", "I"},
    {0b00000000000000000110000000000011, "lwu", "I"},
    {0b00000000000000000011000000100011, "sd", "S"},
    {0b00000000000000000001000000010011, "slli", "I"},
    {0b00000000000000000001000000011011, "slliw", "I"},
    {0b00000000000000000001000000111011, "sllw", "R"},
    {0b01000000000000000101000000010011, "srai", "I"},
    {0b01000000000000000101000000011011, "sraiw", "I"},
    {0b01000000000000000101000000111011, "sraw", "R"},
    {0b00000000000000000101000000010011, "srli", "I"},
    {0b00000000000000000101000000011011, "srliw", "I"},
    {0b00000000000000000101000000111011, "srlw", "R"},
    {0b01000000000000000000000000111011, "subw", "R"},
    {0b00000010000000000101000000111011, "DIVUW", "R"},
    {0b00000010000000000100000000111011, "DIVW", "R"},
    {0b00000010000000000111000000111011, "REMUW", "R"},
    {0b00000010000000000110000000111011, "REMW", "R"},
    {0b00000010000000000000000000111011, "MULW", "R"},
    {0b00000010000000000100000000110011, "DIV", "R"},
    {0b00000010000000000101000000110011, "DIVU", "R"},
    {0b00000010000000000111000000110011, "REMU", "R"},
    {0b00000010000000000110000000110011, "REM", "R"},
    {0b00000010000000000000000000110011, "MUL", "R"},
    {0b00000010000000000001000000110011, "MULH", "R"},
    {0b00000010000000000010000000110011, "MULHSU", "R"},
    {0b00000010000000000011000000110011, "MULHU", "R"},
    {0b00000000000000000000000000110011, "add", "R"},
    {0b00000000000000000000000000010011, "addi", "I"},
    {0b00000000000000000111000000110011, "and", "R"},
    {0b00000000000000000111000000010011, "andi", "I"},
    {0b00000000000000000000000001100011, "beq", "B"},
    {0b00000000000000000101000001100011, "bge", "B"},
    {0b00000000000000000111000001100011, "bgeu", "B"},
    {0b00000000000000000100000001100011, "blt", "B"},
    {0b00000000000000000110000001100011, "bltu", "B"},
    {0b00000000000000000001000001100011, "bne", "B"},
    {0b00000000000000000000000001110011, "ecall", "N"},
    {0b00000000000000000000000000001111, "fence", "N"},
    {0b00000000000000000000000001101111, "jal", "J"},
    {0b00000000000000000000000001100111, "jalr", "I"},
    {0b00000000000000000000000000000011, "lb", "I"},
    {0b00000000000000000100000000000011, "lbu", "I"},
    {0b00000000000000000001000000000011, "lh", "I"},
    {0b00000000000000000101000000000011, "lhu", "I"},
    {0b00000000000000000010000000000011, "lw", "I"},
    {0b00000000000000000110000000110011, "or", "R"},
    {0b00000000000000000110000000010011, "ori", "I"},
    {0b00000000000000000000000000100011, "sb", "S"},
    {0b00000000000000000001000000100011, "sh", "S"},
    {0b00000000000000000010000000100011, "sw", "S"},
    {0b00000000000000000001000000110011, "sll", "R"},
    {0b00000000000000000010000000110011, "slt", "R"},
    {0b00000000000000000010000000010011, "slti", "I"},
    {0b00000000000000000011000000010011, "sltiu", "I"},
    {0b00000000000000000011000000110011, "sltu", "R"},
    {0b01000000000000000101000000110011, "sra", "R"},
    {0b00000000000000000101000000110011, "srl", "R"},
    {0b01000000000000000000000000110011, "sub", "R"},
    {0b00000000000000000100000000110011, "xor", "R"},
    {0b00000000000000000100000000010011, "xori", "I"},
    {0b00000000000100000000000001110011, "ebreak", "N"},
};
#define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
#define InstsLen ARRLEN(insts)

int rand_n(bool sign, int n)
{
  int res = rand() % n;
  if (!sign && res < 0)
    res = -res;
  return res;
}
void print_inst_R(Instruction inst, char *inst_name)
{
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x \tfun3:0x%x \tfun7:0x%x\n", inst.inst, inst.inst_R.op_code, inst.inst_R.funct3, inst.inst_R.funct7);
  printf("\trs1:0x%x \trs2:0x%x \trd:0x%x\n", inst.inst_R.rs1, inst.inst_R.rs2, inst.inst_R.rd);
}
void print_inst_I(Instruction inst, char *inst_name)
{
  uint64_t imm = get_imm_I(inst);
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x \tfun3:0x%x\n", inst.inst, inst.inst_I.op_code, inst.inst_I.funct3);
  printf("\trs1:0x%x \timm:0x%llx \trd:0x%x\n", inst.inst_I.rs1, imm, inst.inst_I.rd);
}
void print_inst_U(Instruction inst, char *inst_name)
{
  uint64_t imm = get_imm_U(inst);
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x \n", inst.inst, inst.inst_U.op_code);
  printf("\timm:0x%llx \trd:0x%x\n", imm, inst.inst_U.rd);
}
void print_inst_S(Instruction inst, char *inst_name)
{
  uint64_t imm = get_imm_S(inst);
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x \tfun3:0x%x\n", inst.inst, inst.inst_S.op_code, inst.inst_S.funct3);
  printf("\trs1:0x%x \trs2:0x%x \timm:0x%llx\n", inst.inst_S.rs1, inst.inst_S.rs2, imm);
}
void print_inst_J(Instruction inst, char *inst_name)
{
  uint64_t imm = get_imm_J(inst);
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x\n", inst.inst, inst.inst_J.op_code);
  printf("\timm:0x%llx \trd:0x%x\n", imm, inst.inst_J.rd);
}
void print_inst_B(Instruction inst, char *inst_name)
{
  uint64_t imm = get_imm_B(inst);
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x \top:0x%x \tfun3:0x%x\n", inst.inst, inst.inst_B.op_code, inst.inst_B.funct3);
  printf("\trs1:0x%x \trs2:0x%x \timm:0llx%x\n", inst.inst_B.rs1, inst.inst_B.rs2, imm);
}
void print_inst_N(Instruction inst, char *inst_name)
{
  printf("instruction : %s\n", inst_name);
  printf("\tinst:0x%x\n", inst.inst);
}
void print_decode_signal(VDecode *decode)
{
  int64_t imm = decode->imm;
  uint8_t rs1 = decode->rs1;
  uint8_t rs2 = decode->rs2;
  uint8_t rd = decode->rootp->Decode__DOT__rd;
  uint8_t opcode = decode->rootp->Decode__DOT__opcode;
  uint8_t funct3 = decode->rootp->Decode__DOT__funct3;
  uint8_t funct7 = decode->rootp->Decode__DOT__funct7;
  Instruction inst = {.inst = decode->inst_i};
  printf("decode result is:\n");
  printf("\tinst:0x%x \top:0x%x \tfun3:0x%x \tfun7:0x%x\n", inst.inst, opcode, funct3, funct7);
  printf("\trs1:0x%x \trs2:0x%x \trd:0x%x\n", rs1, rs2, rd);
  if (decode->rootp->Decode__DOT__op_auipc != 0)
    printf("op_auipc = 1\n");
  if (decode->rootp->Decode__DOT__op_lui != 0)
    printf("op_lui = 1\n");
  if (decode->rootp->Decode__DOT__op_addiw != 0)
    printf("op_addiw = 1\n");
  if (decode->rootp->Decode__DOT__op_addw != 0)
    printf("op_addw = 1\n");
  if (decode->rootp->Decode__DOT__op_ld != 0)
    printf("op_ld = 1\n");
  if (decode->rootp->Decode__DOT__op_lwu != 0)
    printf("op_lwu = 1\n");
  if (decode->rootp->Decode__DOT__op_sd != 0)
    printf("op_sd = 1\n");
  if (decode->rootp->Decode__DOT__op_slli != 0)
    printf("op_slli = 1\n");
  if (decode->rootp->Decode__DOT__op_slliw != 0)
    printf("op_slliw = 1\n");
  if (decode->rootp->Decode__DOT__op_sllw != 0)
    printf("op_sllw = 1\n");
  if (decode->rootp->Decode__DOT__op_srai != 0)
    printf("op_srai = 1\n");
  if (decode->rootp->Decode__DOT__op_sraiw != 0)
    printf("op_sraiw = 1\n");
  if (decode->rootp->Decode__DOT__op_sraw != 0)
    printf("op_sraw = 1\n");
  if (decode->rootp->Decode__DOT__op_srli != 0)
    printf("op_srli = 1\n");
  if (decode->rootp->Decode__DOT__op_srliw != 0)
    printf("op_srliw = 1\n");
  if (decode->rootp->Decode__DOT__op_srlw != 0)
    printf("op_srlw = 1\n");
  if (decode->rootp->Decode__DOT__op_subw != 0)
    printf("op_subw = 1\n");
  if (decode->rootp->Decode__DOT__op_DIVUW != 0)
    printf("op_DIVUW = 1\n");
  if (decode->rootp->Decode__DOT__op_DIVW != 0)
    printf("op_DIVW = 1\n");
  if (decode->rootp->Decode__DOT__op_REMUW != 0)
    printf("op_REMUW = 1\n");
  if (decode->rootp->Decode__DOT__op_REMW != 0)
    printf("op_REMW = 1\n");
  if (decode->rootp->Decode__DOT__op_MULW != 0)
    printf("op_MULW = 1\n");
  if (decode->rootp->Decode__DOT__op_DIV != 0)
    printf("op_DIV = 1\n");
  if (decode->rootp->Decode__DOT__op_DIVU != 0)
    printf("op_DIVU = 1\n");
  if (decode->rootp->Decode__DOT__op_REMU != 0)
    printf("op_REMU = 1\n");
  if (decode->rootp->Decode__DOT__op_REM != 0)
    printf("op_REM = 1\n");
  if (decode->rootp->Decode__DOT__op_MUL != 0)
    printf("op_MUL = 1\n");
  if (decode->rootp->Decode__DOT__op_MULH != 0)
    printf("op_MULH = 1\n");
  if (decode->rootp->Decode__DOT__op_MULHSU != 0)
    printf("op_MULHSU = 1\n");
  if (decode->rootp->Decode__DOT__op_MULHU != 0)
    printf("op_MULHU = 1\n");
  if (decode->rootp->Decode__DOT__op_add != 0)
    printf("op_add = 1\n");
  if (decode->rootp->Decode__DOT__op_addi != 0)
    printf("op_addi = 1\n");
  if (decode->rootp->Decode__DOT__op_and != 0)
    printf("op_and = 1\n");
  if (decode->rootp->Decode__DOT__op_andi != 0)
    printf("op_andi = 1\n");
  if (decode->rootp->Decode__DOT__op_beq != 0)
    printf("op_beq = 1\n");
  if (decode->rootp->Decode__DOT__op_bge != 0)
    printf("op_bge = 1\n");
  if (decode->rootp->Decode__DOT__op_bgeu != 0)
    printf("op_bgeu = 1\n");
  if (decode->rootp->Decode__DOT__op_blt != 0)
    printf("op_blt = 1\n");
  if (decode->rootp->Decode__DOT__op_bltu != 0)
    printf("op_bltu = 1\n");
  if (decode->rootp->Decode__DOT__op_bne != 0)
    printf("op_bne = 1\n");
  if (decode->rootp->Decode__DOT__op_ecall != 0)
    printf("op_ecall = 1\n");
  if (decode->rootp->Decode__DOT__op_fence != 0)
    printf("op_fence = 1\n");
  if (decode->rootp->Decode__DOT__op_jal != 0)
    printf("op_jal = 1\n");
  if (decode->rootp->Decode__DOT__op_jalr != 0)
    printf("op_jalr = 1\n");
  if (decode->rootp->Decode__DOT__op_lb != 0)
    printf("op_lb = 1\n");
  if (decode->rootp->Decode__DOT__op_lbu != 0)
    printf("op_lbu = 1\n");
  if (decode->rootp->Decode__DOT__op_lh != 0)
    printf("op_lh = 1\n");
  if (decode->rootp->Decode__DOT__op_lhu != 0)
    printf("op_lhu = 1\n");
  if (decode->rootp->Decode__DOT__op_lw != 0)
    printf("op_lw = 1\n");
  if (decode->rootp->Decode__DOT__op_or != 0)
    printf("op_or = 1\n");
  if (decode->rootp->Decode__DOT__op_ori != 0)
    printf("op_ori = 1\n");
  if (decode->rootp->Decode__DOT__op_sb != 0)
    printf("op_sb = 1\n");
  if (decode->rootp->Decode__DOT__op_sh != 0)
    printf("op_sh = 1\n");
  if (decode->rootp->Decode__DOT__op_sw != 0)
    printf("op_sw = 1\n");
  if (decode->rootp->Decode__DOT__op_sll != 0)
    printf("op_sll = 1\n");
  if (decode->rootp->Decode__DOT__op_slt != 0)
    printf("op_slt = 1\n");
  if (decode->rootp->Decode__DOT__op_slti != 0)
    printf("op_slti = 1\n");
  if (decode->rootp->Decode__DOT__op_sltiu != 0)
    printf("op_sltiu = 1\n");
  if (decode->rootp->Decode__DOT__op_sltu != 0)
    printf("op_sltu = 1\n");
  if (decode->rootp->Decode__DOT__op_sra != 0)
    printf("op_sra = 1\n");
  if (decode->rootp->Decode__DOT__op_srl != 0)
    printf("op_srl = 1\n");
  if (decode->rootp->Decode__DOT__op_sub != 0)
    printf("op_sub = 1\n");
  if (decode->rootp->Decode__DOT__op_xor != 0)
    printf("op_xor = 1\n");
  if (decode->rootp->Decode__DOT__op_xori != 0)
    printf("op_xori = 1\n");
  if (decode->rootp->Decode__DOT__op_ebreak != 0)
    printf("op_ebreak = 1\n");
  // if(decode->rootp->Decode__DOT__type_I != 0) printf("type_I = 1\n");
  // if(decode->rootp->Decode__DOT__type_U != 0) printf("type_U = 1\n");
  // if(decode->rootp->Decode__DOT__type_S != 0) printf("type_S = 1\n");
  // if(decode->rootp->Decode__DOT__type_J != 0) printf("type_J = 1\n");
  // if(decode->rootp->Decode__DOT__type_B != 0) printf("type_B = 1\n");
  // if(decode->rootp->Decode__DOT__type_R != 0) printf("type_R = 1\n");
  // if(decode->rootp->Decode__DOT__type_N != 0) printf("type_N = 1\n");
  // if(decode->rootp->Decode__DOT__src1_valid != 0) printf("src1_valid = 1\n");
  // if(decode->rootp->Decode__DOT__src2_valid != 0) printf("src2_valid = 1\n");
  return;
}
bool isDecodeOPRight(VDecode *decode, char *inst_name)
{
  if (strcmp("auipc", inst_name) == 0 && decode->rootp->Decode__DOT__op_auipc == 0)
  {
    return false;
  }
  if (strcmp("lui", inst_name) == 0 && decode->rootp->Decode__DOT__op_lui == 0)
  {
    return false;
  }
  if (strcmp("addiw", inst_name) == 0 && decode->rootp->Decode__DOT__op_addiw == 0)
  {
    return false;
  }
  if (strcmp("addw", inst_name) == 0 && decode->rootp->Decode__DOT__op_addw == 0)
  {
    return false;
  }
  if (strcmp("ld", inst_name) == 0 && decode->rootp->Decode__DOT__op_ld == 0)
  {
    return false;
  }
  if (strcmp("lwu", inst_name) == 0 && decode->rootp->Decode__DOT__op_lwu == 0)
  {
    return false;
  }
  if (strcmp("sd", inst_name) == 0 && decode->rootp->Decode__DOT__op_sd == 0)
  {
    return false;
  }
  if (strcmp("slli", inst_name) == 0 && decode->rootp->Decode__DOT__op_slli == 0)
  {
    return false;
  }
  if (strcmp("slliw", inst_name) == 0 && decode->rootp->Decode__DOT__op_slliw == 0)
  {
    return false;
  }
  if (strcmp("sllw", inst_name) == 0 && decode->rootp->Decode__DOT__op_sllw == 0)
  {
    return false;
  }
  if (strcmp("srai", inst_name) == 0 && decode->rootp->Decode__DOT__op_srai == 0)
  {
    return false;
  }
  if (strcmp("sraiw", inst_name) == 0 && decode->rootp->Decode__DOT__op_sraiw == 0)
  {
    return false;
  }
  if (strcmp("sraw", inst_name) == 0 && decode->rootp->Decode__DOT__op_sraw == 0)
  {
    return false;
  }
  if (strcmp("srli", inst_name) == 0 && decode->rootp->Decode__DOT__op_srli == 0)
  {
    return false;
  }
  if (strcmp("srliw", inst_name) == 0 && decode->rootp->Decode__DOT__op_srliw == 0)
  {
    return false;
  }
  if (strcmp("srlw", inst_name) == 0 && decode->rootp->Decode__DOT__op_srlw == 0)
  {
    return false;
  }
  if (strcmp("subw", inst_name) == 0 && decode->rootp->Decode__DOT__op_subw == 0)
  {
    return false;
  }
  if (strcmp("DIVUW", inst_name) == 0 && decode->rootp->Decode__DOT__op_DIVUW == 0)
  {
    return false;
  }
  if (strcmp("DIVW", inst_name) == 0 && decode->rootp->Decode__DOT__op_DIVW == 0)
  {
    return false;
  }
  if (strcmp("REMUW", inst_name) == 0 && decode->rootp->Decode__DOT__op_REMUW == 0)
  {
    return false;
  }
  if (strcmp("REMW", inst_name) == 0 && decode->rootp->Decode__DOT__op_REMW == 0)
  {
    return false;
  }
  if (strcmp("MULW", inst_name) == 0 && decode->rootp->Decode__DOT__op_MULW == 0)
  {
    return false;
  }
  if (strcmp("DIV", inst_name) == 0 && decode->rootp->Decode__DOT__op_DIV == 0)
  {
    return false;
  }
  if (strcmp("DIVU", inst_name) == 0 && decode->rootp->Decode__DOT__op_DIVU == 0)
  {
    return false;
  }
  if (strcmp("REMU", inst_name) == 0 && decode->rootp->Decode__DOT__op_REMU == 0)
  {
    return false;
  }
  if (strcmp("REM", inst_name) == 0 && decode->rootp->Decode__DOT__op_REM == 0)
  {
    return false;
  }
  if (strcmp("MUL", inst_name) == 0 && decode->rootp->Decode__DOT__op_MUL == 0)
  {
    return false;
  }
  if (strcmp("MULH", inst_name) == 0 && decode->rootp->Decode__DOT__op_MULH == 0)
  {
    return false;
  }
  if (strcmp("MULHSU", inst_name) == 0 && decode->rootp->Decode__DOT__op_MULHSU == 0)
  {
    return false;
  }
  if (strcmp("MULHU", inst_name) == 0 && decode->rootp->Decode__DOT__op_MULHU == 0)
  {
    return false;
  }
  if (strcmp("add", inst_name) == 0 && decode->rootp->Decode__DOT__op_add == 0)
  {
    return false;
  }
  if (strcmp("addi", inst_name) == 0 && decode->rootp->Decode__DOT__op_addi == 0)
  {
    return false;
  }
  if (strcmp("and", inst_name) == 0 && decode->rootp->Decode__DOT__op_and == 0)
  {
    return false;
  }
  if (strcmp("andi", inst_name) == 0 && decode->rootp->Decode__DOT__op_andi == 0)
  {
    return false;
  }
  if (strcmp("beq", inst_name) == 0 && decode->rootp->Decode__DOT__op_beq == 0)
  {
    return false;
  }
  if (strcmp("bge", inst_name) == 0 && decode->rootp->Decode__DOT__op_bge == 0)
  {
    return false;
  }
  if (strcmp("bgeu", inst_name) == 0 && decode->rootp->Decode__DOT__op_bgeu == 0)
  {
    return false;
  }
  if (strcmp("blt", inst_name) == 0 && decode->rootp->Decode__DOT__op_blt == 0)
  {
    return false;
  }
  if (strcmp("bltu", inst_name) == 0 && decode->rootp->Decode__DOT__op_bltu == 0)
  {
    return false;
  }
  if (strcmp("bne", inst_name) == 0 && decode->rootp->Decode__DOT__op_bne == 0)
  {
    return false;
  }
  if (strcmp("ecall", inst_name) == 0 && decode->rootp->Decode__DOT__op_ecall == 0)
  {
    return false;
  }
  if (strcmp("fence", inst_name) == 0 && decode->rootp->Decode__DOT__op_fence == 0)
  {
    return false;
  }
  if (strcmp("jal", inst_name) == 0 && decode->rootp->Decode__DOT__op_jal == 0)
  {
    return false;
  }
  if (strcmp("jalr", inst_name) == 0 && decode->rootp->Decode__DOT__op_jalr == 0)
  {
    return false;
  }
  if (strcmp("lb", inst_name) == 0 && decode->rootp->Decode__DOT__op_lb == 0)
  {
    return false;
  }
  if (strcmp("lbu", inst_name) == 0 && decode->rootp->Decode__DOT__op_lbu == 0)
  {
    return false;
  }
  if (strcmp("lh", inst_name) == 0 && decode->rootp->Decode__DOT__op_lh == 0)
  {
    return false;
  }
  if (strcmp("lhu", inst_name) == 0 && decode->rootp->Decode__DOT__op_lhu == 0)
  {
    return false;
  }
  if (strcmp("lw", inst_name) == 0 && decode->rootp->Decode__DOT__op_lw == 0)
  {
    return false;
  }
  if (strcmp("or", inst_name) == 0 && decode->rootp->Decode__DOT__op_or == 0)
  {
    return false;
  }
  if (strcmp("ori", inst_name) == 0 && decode->rootp->Decode__DOT__op_ori == 0)
  {
    return false;
  }
  if (strcmp("sb", inst_name) == 0 && decode->rootp->Decode__DOT__op_sb == 0)
  {
    return false;
  }
  if (strcmp("sh", inst_name) == 0 && decode->rootp->Decode__DOT__op_sh == 0)
  {
    return false;
  }
  if (strcmp("sw", inst_name) == 0 && decode->rootp->Decode__DOT__op_sw == 0)
  {
    return false;
  }
  if (strcmp("sll", inst_name) == 0 && decode->rootp->Decode__DOT__op_sll == 0)
  {
    return false;
  }
  if (strcmp("slt", inst_name) == 0 && decode->rootp->Decode__DOT__op_slt == 0)
  {
    return false;
  }
  if (strcmp("slti", inst_name) == 0 && decode->rootp->Decode__DOT__op_slti == 0)
  {
    return false;
  }
  if (strcmp("sltiu", inst_name) == 0 && decode->rootp->Decode__DOT__op_sltiu == 0)
  {
    return false;
  }
  if (strcmp("sltu", inst_name) == 0 && decode->rootp->Decode__DOT__op_sltu == 0)
  {
    return false;
  }
  if (strcmp("sra", inst_name) == 0 && decode->rootp->Decode__DOT__op_sra == 0)
  {
    return false;
  }
  if (strcmp("srl", inst_name) == 0 && decode->rootp->Decode__DOT__op_srl == 0)
  {
    return false;
  }
  if (strcmp("sub", inst_name) == 0 && decode->rootp->Decode__DOT__op_sub == 0)
  {
    return false;
  }
  if (strcmp("xor", inst_name) == 0 && decode->rootp->Decode__DOT__op_xor == 0)
  {
    return false;
  }
  if (strcmp("xori", inst_name) == 0 && decode->rootp->Decode__DOT__op_xori == 0)
  {
    return false;
  }
  if (strcmp("ebreak", inst_name) == 0 && decode->rootp->Decode__DOT__op_ebreak == 0)
  {
    return false;
  }
  return true;
}

void testInsts(VDecode *decode)
{
  for (int i = 0; i < InstsLen; i++)
  {
    Instruction inst;
    inst.inst = insts[i].inst;
    uint8_t rs1 = rand_n(false, 1 << 5);
    uint8_t rs2 = rand_n(false, 1 << 5);
    uint8_t rd = rand_n(false, 1 << 5);
    uint64_t imm = rand();
    switch (insts[i].type[0])
    {
    case 'I':
      imm = SEXT(imm, 12);
      if (strcmp("slli", insts[i].name) == 0 ||
          strcmp("srli", insts[i].name) == 0 ||
          strcmp("srai", insts[i].name) == 0)
      {
        imm = BITS(imm, 5, 0);
      }
      if (strcmp("slliw", insts[i].name) == 0 ||
          strcmp("srliw", insts[i].name) == 0 ||
          strcmp("sraiw", insts[i].name) == 0)
      {
        imm = BITS(imm, 4, 0);
      }
      if (strcmp("srai", insts[i].name) == 0 || strcmp("sraiw", insts[i].name) == 0)
      {
        imm = BITS(imm, 5, 0) | (0b0100000 << 5);
      }
      inst.inst_I.rs1 = rs1;
      inst.inst_I.rd = rd;
      inst.inst_I.imm_11_0 = BITS(imm, 11, 0);

      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->imm != imm || decode->rootp->Decode__DOT__rd != rd)
      {
        printf("test failed in :\n");
        print_inst_I(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    case 'U':
      imm = SEXT(imm, 20) << 12;
      inst.inst_U.rd = rd;
      inst.inst_U.imm_31_12 = BITS(imm, 31, 12);
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->imm != imm || decode->rootp->Decode__DOT__rd != rd)
      {
        printf("test failed in :\n");
        print_inst_R(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    case 'S':
      imm = SEXT(imm, 12);
      inst.inst_S.rs1 = rs1;
      inst.inst_S.rs2 = rs2;
      inst.inst_S.imm_4_0 = BITS(imm, 4, 0);
      inst.inst_S.imm_11_5 = BITS(imm, 11, 5);
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->imm != imm || decode->rs1 != rs1 || decode->rs2 != rs2)
      {
        printf("test failed in :\n");
        print_inst_S(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    case 'R':
      inst.inst_R.rd = rd;
      inst.inst_R.rs1 = rs1;
      inst.inst_R.rs2 = rs2;
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->rs1 != rs1 || decode->rs2 != rs2 || decode->rootp->Decode__DOT__rd != rd)
      {
        printf("test failed in :\n");
        print_inst_R(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    case 'J':
      imm = SEXT(imm, 20) << 1;
      inst.inst_J.rd = rd;
      inst.inst_J.imm_10_1 = BITS(imm, 10, 1);
      inst.inst_J.imm_11 = BITS(imm, 11, 11);
      inst.inst_J.imm_19_12 = BITS(imm, 19, 12);
      inst.inst_J.imm_20 = BITS(imm, 20, 20);
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->imm != imm || decode->rootp->Decode__DOT__rd != rd)
      {
        printf("test failed in :\n");
        print_inst_J(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    case 'B':
      imm = SEXT(imm, 12) << 1;
      inst.inst_B.rs1 = rs1;
      inst.inst_B.rs2 = rs2;
      inst.inst_B.imm_10_5 = BITS(imm, 10, 5);
      inst.inst_B.imm_11 = BITS(imm, 11, 11);
      inst.inst_B.imm_12 = BITS(imm, 12, 12);
      inst.inst_B.imm_4_1 = BITS(imm, 4, 1);
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false || decode->imm != imm || decode->rs1 != rs1 || decode->rs2 != rs2)
      {
        printf("test failed in :\n");
        print_inst_B(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
      break;
    case 'N':
      decode->inst_i = inst.inst;
      decode->eval();
      if (isDecodeOPRight(decode, insts[i].name) == false)
      {
        print_inst_N(inst, insts[i].name);
        print_decode_signal(decode);
      }
      break;
    default:
      assert(0);
      break;
    }
    // print_decode_signal(decode);
  }

  return;
}
void testInst_I(VDecode *decode, int test_cnt)
{
  Instruction inst_addi;
  int index = 0;

  printf("test begin\n");
  for (int i = 0; i < test_cnt; i++)
  {
    for (; index < InstsLen; index = (index + 1) % InstsLen)
    {
      if (insts[index].type[0] == 'I')
      {
        inst_addi.inst = insts[index].inst;
        break;
      }
    }
    int64_t imm = SEXT(rand_n(true, 1 << 12), 12);
    uint8_t rd = rand_n(false, 1 << 5);
    inst_addi.inst_I.imm_11_0 = imm;
    inst_addi.inst_I.rd = rd;

    decode->inst_i = inst_addi.inst;
    decode->eval();
    int64_t decode_imm = decode->imm;
    uint8_t decode_rd = decode->rootp->Decode__DOT__rd;
    uint8_t deocde_op_addi = decode->rootp->Decode__DOT__op_addi;
    if (isDecodeOPRight(decode, insts[index].name) == false || decode_imm != imm || decode_rd != rd)
    {
      printf("test failed in :\n");
      print_inst_I(inst_addi, insts[index].name);
      print_decode_signal(decode);
    }
  }
  printf("test end\n");
  return;
}

int main(int argc, char **argv, char **env)
{
  Verilated::commandArgs(argc, argv);
  VDecode *top = new VDecode;
  srand(time(0));
  // Instruction inst_add;
  // inst_add.inst_R.op_code = 0b0110011;
  // inst_add.inst_R.funct3 = 0;
  // inst_add.inst_R.funct7 = 0;

  // inst_add.inst_R.rd = 0b01001;
  // inst_add.inst_R.rs1 = 0b10100;
  // inst_add.inst_R.rs2 = 0b10010;

  // top->inst = inst_add.inst;
  // top->eval();
  // print_inst_R(inst_add,"add");
  // print_decode_signal(top);

  // testInst_I(top,10000);

  printf("inst decode test begin\n");
  int test_loop = 1000000 / InstsLen + 1;
  struct timespec now;
  clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
  uint64_t start_us = now.tv_sec * 1000000 + now.tv_nsec / 1000;
  for (int i = 0; i < test_loop; i++)
  {
    testInsts(top);
  }
  clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
  uint64_t end_us = now.tv_sec * 1000000 + now.tv_nsec / 1000;

  printf("test cost time : %ldms\n", (end_us - start_us) / 1000);
  printf("test insts is %d\n", test_loop * InstsLen);
  printf("test speed is %d inst/ms\n", (int)(test_loop * InstsLen / ((end_us - start_us) / 1000)));
  printf("inst decode test end\n");
  delete top;
  exit(0);

  while (!Verilated::gotFinish())
  {
    top->eval();
    print_decode_signal(top);
  }
  delete top;
  exit(0);
}
#ifdef __cplusplus
extern "C"
{
#endif

    // DPI IMPORTS
    long long mem_read(long long raddr, svBit is_icache) { return 0; }
    void mem_write(long long waddr, long long wdata, char wmask) { return; }
    void other_inst(svBit ecall, svBit fence, svBit ebreak) { return; }
    long long pmem_read(long long raddr, char rsize, char is_icache) { return 0; }
    void pmem_write(long long waddr, long long wdata, char wmask) { return; }
    void raise_hard_intr() {}
    void submit_inst(long long pc, int inst, long long next_pc) {}
    void difftest_memory_access(long long addr) {}

#ifdef __cplusplus
}
#endif